package lifeOfAFish.scenegraph;

import java.util.*;
import javax.media.opengl.*;

/**
 * The most fundamental class in the scene graph: a node. 
 * @author Erik Bonner
 *
 */
public class sgNode {
	
	protected Vector<sgNode> m_children; 
	protected sgNode m_parent = null;
	protected sgVec3 m_globalCoords = new sgVec3();
	protected sgMatrix3D m_matrix = new sgMatrix3D();
	protected String m_name = "Node";
	
	
	/**
	 * Default constructor
	 */
	public sgNode() {
		m_children = new Vector<sgNode>();
	}
	
	/**
	 * The function for rendering the node. 
	 * This needs to be implemented by children. 
	 */
	public void render() {};
	
	/**
	 * Add a child to this node
	 * @return the child index
	 */
	public int addChild(sgNode node){
		m_children.add(node);
		node.m_parent = this;
		return m_children.size()-1;
	}
	
	/**
	 * Searches children for given node, and, if found, removes it. 
	 */
	public void removeChild(sgNode node){
		for (int i = 0; i < m_children.size(); i++)
		{
			if (m_children.get(i) == node)
			{
				m_children.remove(i);
				break;
			}
		} 
	}
	
	/**
	 * remove a child by index
	 */
	public void removeChild(int index){
		if (index >= 0 && index < m_children.size())
			m_children.remove(index);
	}
	
	
	
	/**
	 * return the number of children
	 */
	public int getNumberOfChildren()
	{
		return m_children.size();
	}
	
	/**
	 * For printing the state of the node
	 */
	public String toString() {
		
		String str = this.getClass().getName();
		
		for (int i = 0; i < m_children.size(); i++){
			str += "\n" + m_children.toString();
		}
		
		return str;
//		return "Number of children: " + m_children.size();
	}
	
	/**
	 * Traverse this node, and all of its children
	 */
	public void traverse(){
		GL gl = sgGlobals.gl;
		
		gl.glPushMatrix();
		this.push();
		render();
		for (int i = 0; i < m_children.size(); i++){
			m_children.get(i).traverse();
		}
		this.pop();
		gl.glPopMatrix();
	}
	
	/**
	 * To be overridden by any children that may want to call additional
	 * stack pushes during traversal, such as glPushAttrib
	 */
	protected void push () {}
	
	/**
	 * To be overridden by any children that may want to call additional
	 * stack pops during traversal, such as glPopAttrib
	 */
	protected void pop() {}
	
	/**
	 * Return the global coordinates of this node
	 */
	public sgVec3 getGlobalCoords()
	{
//		return new sgVec3(this.m_globalCoords);
		return computeGlobalCoords(new sgVec3(0.0f, 1.0f, 0.0f));
	}
	
	/**
	 * Compute the global coordinates of this node
	 */
	protected sgVec3 computeGlobalCoords(sgVec3 vec)
	{
		
		// first, retrieve the transformation list leading to this node
		Vector<sgMatrix3D> matList = new Vector<sgMatrix3D>();
		getTransformList(matList);
		
		// now, multiply our way along the matrix list 
		sgMatrix3D result = matList.get(0);
		for (int i = 1; i < matList.size(); i++)
		{
			result = sgMatrix3D.multiply(matList.get(i), result);
		}
		
		// now apply the result to the input vector
		sgVec3 ret = sgVec3.multiply(result.get1D(), vec);
		
		// return the result
		return ret;
	}
	
	protected void getTransformList(Vector<sgMatrix3D> matList){
		if (m_parent != null) m_parent.getTransformList(matList);
		matList.add(m_matrix);
	}
	
	/**
	 * Set name of this node
	 */
	public void setName(String name){
		m_name = name;
	}
	
	/**
	 * Get name of this node
	 */
	public String getName(){
		return m_name;
	}
	
	
}
